{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "deedcdd7-a508-4fb3-b1cb-43f9fcebd5ea",
   "metadata": {},
   "source": [
    "## 文件读写操作"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "516de1a7-3af0-4626-b510-cb6f9a75ee86",
   "metadata": {},
   "outputs": [
    {
     "ename": "FileNotFoundError",
     "evalue": "[Errno 2] No such file or directory: './a.txt'",
     "output_type": "error",
     "traceback": [
      "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[1;31mFileNotFoundError\u001b[0m                         Traceback (most recent call last)",
      "Cell \u001b[1;32mIn[1], line 4\u001b[0m\n\u001b[0;32m      1\u001b[0m \u001b[38;5;66;03m#coding:UTF-8\u001b[39;00m\n\u001b[0;32m      2\u001b[0m \u001b[38;5;66;03m#1.打开文件，由应用程序向操作系统发起系统调用用open(...),操作系统打开该文件，对应一块硬盘空间，并返回一个文件对象赋值给一个变量f\u001b[39;00m\n\u001b[1;32m----> 4\u001b[0m f \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mopen\u001b[39m(\u001b[38;5;124m'\u001b[39m\u001b[38;5;124m./a.txt\u001b[39m\u001b[38;5;124m'\u001b[39m, \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mr\u001b[39m\u001b[38;5;124m'\u001b[39m, encoding\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mutf-8\u001b[39m\u001b[38;5;124m'\u001b[39m)    \u001b[38;5;66;03m#默认打开模式就为r, r表示read读\u001b[39;00m\n\u001b[0;32m      6\u001b[0m \u001b[38;5;66;03m#2. 调用文件对象下的读/写方法，会被操作系统转换为读/写硬盘的操作\u001b[39;00m\n\u001b[0;32m      7\u001b[0m data \u001b[38;5;241m=\u001b[39m f\u001b[38;5;241m.\u001b[39mread()\n",
      "File \u001b[1;32mD:\\anaconda3\\Lib\\site-packages\\IPython\\core\\interactiveshell.py:324\u001b[0m, in \u001b[0;36m_modified_open\u001b[1;34m(file, *args, **kwargs)\u001b[0m\n\u001b[0;32m    317\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m file \u001b[38;5;129;01min\u001b[39;00m {\u001b[38;5;241m0\u001b[39m, \u001b[38;5;241m1\u001b[39m, \u001b[38;5;241m2\u001b[39m}:\n\u001b[0;32m    318\u001b[0m     \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(\n\u001b[0;32m    319\u001b[0m         \u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mIPython won\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mt let you open fd=\u001b[39m\u001b[38;5;132;01m{\u001b[39;00mfile\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m by default \u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[0;32m    320\u001b[0m         \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mas it is likely to crash IPython. If you know what you are doing, \u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[0;32m    321\u001b[0m         \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124myou can use builtins\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124m open.\u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[0;32m    322\u001b[0m     )\n\u001b[1;32m--> 324\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m io_open(file, \u001b[38;5;241m*\u001b[39margs, \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mkwargs)\n",
      "\u001b[1;31mFileNotFoundError\u001b[0m: [Errno 2] No such file or directory: './a.txt'"
     ]
    }
   ],
   "source": [
    "#coding:UTF-8\n",
    "#1.打开文件，由应用程序向操作系统发起系统调用用open(...),操作系统打开该文件，对应一块硬盘空间，并返回一个文件对象赋值给一个变量f\n",
    "\n",
    "f = open('./a.txt', 'r', encoding='utf-8')    #默认打开模式就为r, r表示read读\n",
    "\n",
    "#2. 调用文件对象下的读/写方法，会被操作系统转换为读/写硬盘的操作\n",
    "data = f.read()\n",
    "print(data)\n",
    "\n",
    "#3. 向操作系统发起关闭文件的请求，回收系统资源\n",
    "f.close()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "889d488d-0ca2-44bf-a226-170dcfc12fa3",
   "metadata": {},
   "source": [
    "### 资源回收与with上下文管理\n",
    "打开一个文件包含两部分资源：应用程序的变量f和操作系统打开的文件。在操作完毕一个文件时，必须把与该文件的这两部分资源全部回收，回收方法为："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "33712388-18ba-4de1-94bb-5b8dde040541",
   "metadata": {},
   "outputs": [],
   "source": [
    "f.close()    #回收操作系统打开的文件资源\n",
    "\n",
    "del f    #回收应用程序的变量"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ce30ed65-a398-4388-abeb-402a40b33723",
   "metadata": {},
   "source": [
    "其中 del f 一定要发生在f.close() 之后，否则就会导致操作系统打开的文件无法关闭，白白占用资源，而Python自动的垃圾回收机制决定了我们无需考虑"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "e71b8e9a-9ae8-4a56-96af-cb98310afaf0",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 通过with管理上下文\n",
    "# 1.在执行完子代码块后，with会自动执行f.close()\n",
    "with open('./a.txt', 'w') as f:\n",
    "    pass\n",
    "\n",
    "#2.可用with同时打开多个文件，用逗号分隔开即可\n",
    "with open('./a.txt', 'r') as read_f, open('./b.txt', 'w') as write_f:\n",
    "    data = read_f.read()\n",
    "    write_f.write(data)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ecb0e578-f69d-4cac-8a26-9003c7011aa1",
   "metadata": {},
   "source": [
    "### 指定操作文本文件的字符编码\n",
    "f = open(...)是由操作系统打开文件，如果打开的是文本文件，会涉及到字符编码问题，如果没有为open指定编码，那么打开文本文件的默认编码很明显是操作系统说了算的，操作系统会用自己的默认编码去打开文件，在Windows中是gbk,在Linux中是utf-8,防止乱码的诀窍：文件以什么方式存的，就要以什么方式打开\n",
    "f.open('./a.txt' 'r' encoding='utf-8')"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "bb6442af-046b-4b58-9399-ef34395bd7de",
   "metadata": {},
   "source": [
    "### 文件的操作模式\n",
    "### 控制文件读写操作的模式\n",
    "- r(默认的)：只读\n",
    "- w: 只写\n",
    "- a: 只追加写"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "1e1443ef-80d3-416f-ba8a-4703bf231466",
   "metadata": {},
   "outputs": [
    {
     "name": "stdin",
     "output_type": "stream",
     "text": [
      "请输入你的名字： zhangsan\n"
     ]
    },
    {
     "ename": "AttributeError",
     "evalue": "'str' object has no attribute 'strp'",
     "output_type": "error",
     "traceback": [
      "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[1;31mAttributeError\u001b[0m                            Traceback (most recent call last)",
      "Cell \u001b[1;32mIn[6], line 6\u001b[0m\n\u001b[0;32m      3\u001b[0m     res \u001b[38;5;241m=\u001b[39m f\u001b[38;5;241m.\u001b[39mread()    \u001b[38;5;66;03m# 会将文件的内容由硬盘全部读入内存，赋值给res\u001b[39;00m\n\u001b[0;32m      5\u001b[0m \u001b[38;5;66;03m# 实现用户认证功能\u001b[39;00m\n\u001b[1;32m----> 6\u001b[0m inp_name \u001b[38;5;241m=\u001b[39m \u001b[38;5;28minput\u001b[39m(\u001b[38;5;124m'\u001b[39m\u001b[38;5;124m请输入你的名字：\u001b[39m\u001b[38;5;124m'\u001b[39m)\u001b[38;5;241m.\u001b[39mstrp()\n\u001b[0;32m      7\u001b[0m inp_pwd \u001b[38;5;241m=\u001b[39m \u001b[38;5;28minput\u001b[39m(\u001b[38;5;124m'\u001b[39m\u001b[38;5;124m请输入你的密码：\u001b[39m\u001b[38;5;124m'\u001b[39m)\u001b[38;5;241m.\u001b[39mstrp()\n\u001b[0;32m      8\u001b[0m \u001b[38;5;28;01mwith\u001b[39;00m \u001b[38;5;28mopen\u001b[39m(\u001b[38;5;124mr\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mdb.txt\u001b[39m\u001b[38;5;124m'\u001b[39m, mode\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mr\u001b[39m\u001b[38;5;124m'\u001b[39m, encoding\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mutf-8\u001b[39m\u001b[38;5;124m'\u001b[39m) \u001b[38;5;28;01mas\u001b[39;00m f:\n",
      "\u001b[1;31mAttributeError\u001b[0m: 'str' object has no attribute 'strp'"
     ]
    }
   ],
   "source": [
    "# r只读模式\n",
    "with open('./a.txt', mode='r', encoding='utf-8') as f:\n",
    "    res = f.read()    # 会将文件的内容由硬盘全部读入内存，赋值给res\n",
    "\n",
    "# 实现用户认证功能\n",
    "inp_name = input('请输入你的名字：').strp()\n",
    "inp_pwd = input('请输入你的密码：').strp()\n",
    "with open(r'db.txt', mode='r', encoding='utf-8') as f:\n",
    "    for line in f:\n",
    "        #把用户输入的名字和密码与读出的内容做对比\n",
    "        u, p = line.strip('\\n').split(':')\n",
    "        if inp_name == u and inp_pwd == p:\n",
    "            print('登陆成功')\n",
    "            break\n",
    "        else:\n",
    "            print(账号或密码错误)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "019e1eba-d8df-45ba-bc8d-58b37e475ace",
   "metadata": {},
   "source": [
    "w模式的使用"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "e4a21d13-c9c8-4bcf-89c5-27c231b4e319",
   "metadata": {},
   "outputs": [],
   "source": [
    "# w只写模式\n",
    "with open('./b.txt', mode='w', encoding='utf-8') as f:\n",
    "    f.write('你好\\n')\n",
    "    f.write('数据写入到文档中\\n')\n",
    "    f.write('数据持久化保存\\n')\n",
    "    f.write('可完善之前的所有项目\\n')\n",
    "    f.write('111\\n222\\n333\\n')"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a6474a90-6489-4e69-a4c7-39551d8705c2",
   "metadata": {},
   "source": [
    "注意：\n",
    "1.在文件不关闭的情况下，连续的写入，后写内容一定跟在先写内容的后面\n",
    "2.如果重新以w 模式打开文件，则会清空文件内容"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "74c0bb07-442f-49e8-bbe9-8a80463356e8",
   "metadata": {},
   "source": [
    "a模式的使用\n",
    "a只追加"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "2223ff5a-3536-42ba-9a26-7ef1c96cdfd5",
   "metadata": {},
   "outputs": [],
   "source": [
    "#a模式的使用\n",
    "with open('./c.txt', mode='a', encoding='utf-8') as f:\n",
    "    f.write('44444\\n')\n",
    "    f.write('55555\\n')\n",
    "\n",
    "#完成注册功能\n",
    "name = input('username>>>：').strp()\n",
    "pwd = input('password>>>:').strip()\n",
    "    with open('./db1.txt', mode='a', encoding='utf-8') as f:\n",
    "        info = '%s:%s\\n' % (name,pwd)\n",
    "        f.write(info)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b68ef8d3-8e32-437c-96b3-cdc604ba978f",
   "metadata": {},
   "source": [
    "> w模式与a模式的异同：\n",
    "> 1.相同点：在打开的文件不关闭的情况下，连续的写入，新的内容会跟在写前的内容之后\n",
    "> 2.不同点：以a模式重新打打开文件，不会清空清空内容，会将文件指针直接移动到文件末尾，新写的内容永远在最后"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e8d46872-9ca7-4786-8554-1725b57ae563",
   "metadata": {},
   "source": [
    "+模式\n",
    "r+ w+ a+:可读可写"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ce2aafc5-a096-4872-88f5-1ce43eb31f9c",
   "metadata": {},
   "source": [
    "### 控制文件读写内容的模式\n",
    "T（默认的）：文本模式\n",
    "1.读写文件都是以字符串为单位的\n",
    "2.只能针对文本文件\n",
    "3.必须指定encoding参数\n",
    "b:二进制模式\n",
    "1.读写文件都是以byte二进制为单位的\n",
    "2.可以针对所有文件（主要针对）"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "d705df17-47d3-454b-89d9-c3e15e78c602",
   "metadata": {},
   "outputs": [],
   "source": [
    "# t模式的使用：如股票我们指定的文件打开模式为r/w/a\n",
    "with open('./a.txt', mode='rt', encoding='utf-8') as f:\n",
    "    res = f.read()\n",
    "    print(type(res))    # 输出结果<calss 'str'>表示当前文档内容是字符串格式\n",
    "\n",
    "with open('./a.txt', mode='wt', encoding='utf-8') as f:\n",
    "    s = 'abc'\n",
    "    f.write(s)    # 写入的也必须是字符串类型"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "8d6251b4-3b9a-4d6a-8a4e-33091bd06865",
   "metadata": {},
   "source": [
    "注意：t 模式只能用于操作文本文件，无论读写，都应该以字符串为单位，而存取硬盘本质都是二进制的形式，当指定t模式时，内部帮我们做了编码和解码"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "d96a4e71-4a90-41ef-83c8-d814641c9005",
   "metadata": {},
   "outputs": [
    {
     "ename": "SyntaxError",
     "evalue": "invalid character '：' (U+FF1A) (3974450967.py, line 1)",
     "output_type": "error",
     "traceback": [
      "\u001b[1;36m  Cell \u001b[1;32mIn[9], line 1\u001b[1;36m\u001b[0m\n\u001b[1;33m    b模式的使用：读写都是以二进制为单位\u001b[0m\n\u001b[1;37m          ^\u001b[0m\n\u001b[1;31mSyntaxError\u001b[0m\u001b[1;31m:\u001b[0m invalid character '：' (U+FF1A)\n"
     ]
    }
   ],
   "source": [
    "b模式的使用：读写都是以二进制为单位\n",
    "with open('./1.mp4', mode='rb') as f:\n",
    "    data = f.read()\n",
    "    print(type(data))    # 输出结果为<class 'bytes'>\n",
    "\n",
    "with open('./a.txt', mode='wb') as f:\n",
    "    msg = 'AI神经网络'\n",
    "    res = mag.encode('utf-8')    # res为bytes类型\n",
    "    f.write(res)    # 在b模式中写入文件的只能是bytes类型\n",
    "\n",
    "# 编写拷贝工具\n",
    "src_file = input('源文件路径：/n').strip()\n",
    "src_file = input('目标文件路径：/n').strip()\n",
    "with open(r'%s' % src_file, mode='rb') as read_f, open(r'%s' % dst_file, mode='wb') as write_f:\n",
    "    for line in read_f:\n",
    "        print(line)\n",
    "        write_f.write(line)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "007229cd-7181-4b56-8903-4918c1fdb765",
   "metadata": {},
   "source": [
    "> b模式对比t模式\n",
    "> 1.在操作纯文本方面t模式帮我们省去了编码和解码的环节，b模式则需要手动编码和解码，所以t模式更为方便\n",
    "> 2，针对非文本文件（图片、视频、音频等）只能使用b模式"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e5ab8d8c-3e82-44ae-9eb7-7d0464561c57",
   "metadata": {},
   "source": [
    "### 操作文件的方法\n",
    "### 读操作\n",
    "- f.read():读取所有内容，执行完该文件后，文件指针会移动到文件末尾\n",
    "- f.readline():读取一行内容，光标移动到第二行首部\n",
    "- f.readlines(): "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "04df0a30-030f-463d-aa26-c3c4ebd00463",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 方式一\n",
    "with open('./a.txt', mode='rt',encoding='utf-8') as f:\n",
    "    for line in f:\n",
    "        print(line)    # 同一时刻只一行内容到内存中\n",
    "\n",
    "#方式二\n",
    "with open('1.mp4', mode='rb') as f:\n",
    "    while True:\n",
    "        # 1TB = 1024GB\n",
    "        # 1GB = 1024MB\n",
    "        # 1MB = 1024KB\n",
    "        data = f.read(1024)    # 同一时刻只读入1024个Bytes列表到内存中\n",
    "        if len(data) == 0:\n",
    "            break\n",
    "print(data)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0b7a8de5-1579-453e-9f67-171dce84a97d",
   "metadata": {},
   "source": [
    "### 写操作"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "5903cb3f-286c-44e7-a297-a4af9377bd13",
   "metadata": {},
   "source": [
    "f.write('1111\\n222\\n')   #针对文本模式的写，需要自己写换行符\n",
    "\n",
    "f.write('1111\\n222\\n'.encoding('utf-8'))    #针对b模式的写，需要自己写换行符\n",
    "\n",
    "f.writeline(['333\\n', '444\\n'])   #文件模式\n",
    "\n",
    "f.writelines([bytes('333\\n', encoding='utf-8'), '444\\n'.encode('utf-8')])   # b模式\n",
    "\n",
    "- f.readable()文件是否可读\n",
    "- f.writable()\n",
    "- f.closed文件是否关闭\n",
    "- f.encoding如果文件打开模式为b，则没有该属性\n",
    "- f."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "bf58403d-c132-4129-a8e9-f4d9dc8caed1",
   "metadata": {},
   "outputs": [],
   "source": [
    "with open('./a.txt', mode='rt',encoding='utf-8') as f:\n",
    "    data = f.read(3)    #读取3个字符\n",
    "    print(data)\n",
    "\n",
    "with open('./a.txt', mode='rt') as f:\n",
    "    data = f.read(3)    #读取3个Bytes\n",
    "    print(data)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b3801490-9531-4cb3-b131-2d840d7723a0",
   "metadata": {},
   "source": [
    "前面文件内指针的移动都是由读/写操作而被动触发的，若想读取文件某一特定的位置的数据，则需要使用f.seek()方法主动控制文件内指针的移动：\n",
    "f.seek(指针移动的字节数， 模式控制)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "499d3207-9ad1-4cc6-ad2b-6df992696479",
   "metadata": {},
   "source": [
    "### 模式控制\n",
    "- 0默认模式，该模式代表指针移动的字节数是以文件开头为参照物的\n",
    "- "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "9f23f1eb-12dd-4fc6-a5c7-b5cab0c4883d",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "3\n",
      "\n"
     ]
    },
    {
     "ename": "AttributeError",
     "evalue": "'str' object has no attribute 'decode'",
     "output_type": "error",
     "traceback": [
      "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[1;31mAttributeError\u001b[0m                            Traceback (most recent call last)",
      "Cell \u001b[1;32mIn[11], line 11\u001b[0m\n\u001b[0;32m      9\u001b[0m \u001b[38;5;28;01mwith\u001b[39;00m \u001b[38;5;28mopen\u001b[39m(\u001b[38;5;124m'\u001b[39m\u001b[38;5;124m./a.txt\u001b[39m\u001b[38;5;124m'\u001b[39m, mode\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mrt\u001b[39m\u001b[38;5;124m'\u001b[39m) \u001b[38;5;28;01mas\u001b[39;00m f:\n\u001b[0;32m     10\u001b[0m     f\u001b[38;5;241m.\u001b[39mseek(\u001b[38;5;241m6\u001b[39m, \u001b[38;5;241m0\u001b[39m)\n\u001b[1;32m---> 11\u001b[0m     \u001b[38;5;28mprint\u001b[39m(f\u001b[38;5;241m.\u001b[39mread()\u001b[38;5;241m.\u001b[39mdecode(\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mutf-8\u001b[39m\u001b[38;5;124m'\u001b[39m))\n",
      "\u001b[1;31mAttributeError\u001b[0m: 'str' object has no attribute 'decode'"
     ]
    }
   ],
   "source": [
    "# 0模式\n",
    "# a.txt用utf-8编码\n",
    "with open('./a.txt', mode='rt',encoding='utf-8') as f:\n",
    "    f.seek(3, 0)    #参照文件开头移动3个字节\n",
    "    print(f.tell())    #查看当前文件指针距离文件开头的位置，输出结果\n",
    "    print(f.read())    #从第3个字节的位置读到文件夹末尾，输出结果\n",
    "#注意：t模式下，会将读取的内容自动解码，所以必须保证读取的内容是一个完整的中文数据，否则解码失败\n",
    "\n",
    "with open('./a.txt', mode='rt') as f:\n",
    "    f.seek(6, 0)\n",
    "    print(f.read().decode('utf-8'))    #输出结果"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "id": "49f876a0-024a-4df4-b9fd-5d330ccafc5d",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "3\n",
      "7\n"
     ]
    }
   ],
   "source": [
    "# 1模式\n",
    "with open('./a.txt', mode='rb') as f:\n",
    "    f.seek(3, 1)    #从当前位置往后移动3个字节，而此时的当前位置就是文件开头\n",
    "    print(f.tell())    #输出结果3\n",
    "    f.seek(4, 1)    #从当前位置往后移动4个字节，而此时的当前位置为3\n",
    "    print(f.tell())    #输出结果7"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "id": "352c2299-2820-4d19-bda8-167afa3991be",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0\n"
     ]
    },
    {
     "ename": "OSError",
     "evalue": "[Errno 22] Invalid argument",
     "output_type": "error",
     "traceback": [
      "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[1;31mOSError\u001b[0m                                   Traceback (most recent call last)",
      "Cell \u001b[1;32mIn[16], line 5\u001b[0m\n\u001b[0;32m      3\u001b[0m f\u001b[38;5;241m.\u001b[39mseek(\u001b[38;5;241m0\u001b[39m, \u001b[38;5;241m2\u001b[39m)    \u001b[38;5;66;03m#参照文件末尾移动0个字节，即直接跳到文件末尾\u001b[39;00m\n\u001b[0;32m      4\u001b[0m \u001b[38;5;28mprint\u001b[39m(f\u001b[38;5;241m.\u001b[39mtell())    \u001b[38;5;66;03m#输出结果9\u001b[39;00m\n\u001b[1;32m----> 5\u001b[0m f\u001b[38;5;241m.\u001b[39mseek(\u001b[38;5;241m-\u001b[39m\u001b[38;5;241m3\u001b[39m, \u001b[38;5;241m2\u001b[39m)    \u001b[38;5;66;03m#参照文件末尾往前移动3个字节\u001b[39;00m\n\u001b[0;32m      6\u001b[0m \u001b[38;5;28mprint\u001b[39m(f\u001b[38;5;241m.\u001b[39mread()\u001b[38;5;241m.\u001b[39mdecode(\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mutf-8\u001b[39m\u001b[38;5;124m'\u001b[39m))\n",
      "\u001b[1;31mOSError\u001b[0m: [Errno 22] Invalid argument"
     ]
    }
   ],
   "source": [
    "# 2模式\n",
    "with open('./a.txt', mode='rb') as f:\n",
    "    f.seek(0, 2)    #参照文件末尾移动0个字节，即直接跳到文件末尾\n",
    "    print(f.tell())    #输出结果9\n",
    "    f.seek(-3, 2)    #参照文件末尾往前移动3个字节\n",
    "    print(f.read().decode('utf-8'))    #输出结果"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "id": "3b9e0af1-f28a-47ce-9ac1-ad03c29c94d0",
   "metadata": {},
   "outputs": [
    {
     "ename": "ValueError",
     "evalue": "binary mode doesn't take an encoding argument",
     "output_type": "error",
     "traceback": [
      "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[1;31mValueError\u001b[0m                                Traceback (most recent call last)",
      "Cell \u001b[1;32mIn[18], line 3\u001b[0m\n\u001b[0;32m      1\u001b[0m \u001b[38;5;66;03m#文件的修改\u001b[39;00m\n\u001b[0;32m      2\u001b[0m \u001b[38;5;66;03m#0模式的使用\u001b[39;00m\n\u001b[1;32m----> 3\u001b[0m \u001b[38;5;28;01mwith\u001b[39;00m \u001b[38;5;28mopen\u001b[39m(\u001b[38;5;124m'\u001b[39m\u001b[38;5;124m./a.txt\u001b[39m\u001b[38;5;124m'\u001b[39m, mode\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mrb\u001b[39m\u001b[38;5;124m'\u001b[39m,encoding\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mutf-8\u001b[39m\u001b[38;5;124m'\u001b[39m) \u001b[38;5;28;01mas\u001b[39;00m f:\n\u001b[0;32m      4\u001b[0m     f\u001b[38;5;241m.\u001b[39mseek(\u001b[38;5;241m3\u001b[39m, \u001b[38;5;241m0\u001b[39m)    \u001b[38;5;66;03m#参照文件开头移动了3个字节\u001b[39;00m\n\u001b[0;32m      5\u001b[0m     \u001b[38;5;28mprint\u001b[39m(f\u001b[38;5;241m.\u001b[39mtell())    \u001b[38;5;66;03m#查看当前文件指针距离文件开头的位置，输出结果是3\u001b[39;00m\n",
      "File \u001b[1;32mD:\\anaconda3\\Lib\\site-packages\\IPython\\core\\interactiveshell.py:324\u001b[0m, in \u001b[0;36m_modified_open\u001b[1;34m(file, *args, **kwargs)\u001b[0m\n\u001b[0;32m    317\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m file \u001b[38;5;129;01min\u001b[39;00m {\u001b[38;5;241m0\u001b[39m, \u001b[38;5;241m1\u001b[39m, \u001b[38;5;241m2\u001b[39m}:\n\u001b[0;32m    318\u001b[0m     \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(\n\u001b[0;32m    319\u001b[0m         \u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mIPython won\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mt let you open fd=\u001b[39m\u001b[38;5;132;01m{\u001b[39;00mfile\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m by default \u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[0;32m    320\u001b[0m         \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mas it is likely to crash IPython. If you know what you are doing, \u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[0;32m    321\u001b[0m         \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124myou can use builtins\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124m open.\u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[0;32m    322\u001b[0m     )\n\u001b[1;32m--> 324\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m io_open(file, \u001b[38;5;241m*\u001b[39margs, \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mkwargs)\n",
      "\u001b[1;31mValueError\u001b[0m: binary mode doesn't take an encoding argument"
     ]
    }
   ],
   "source": [
    "#文件的修改\n",
    "#0模式的使用\n",
    "with open('./a.txt', mode='rb',encoding='utf-8') as f:\n",
    "    f.seek(3, 0)    #参照文件开头移动了3个字节\n",
    "    print(f.tell())    #查看当前文件指针距离文件开头的位置，输出结果是3\n",
    "    print(f.read())    #从第3个字节的位置读到文件末尾，输出结果\n",
    "    # 注意：在t模式中，会将读取的内容自动解码\n",
    "\n",
    "with open('./a.txt', mode='rb') as f:\n",
    "    f.seek(6, 0)\n",
    "    print(f.read().decode('utf-8'))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "59bea172-32b3-4102-8c16-cf6ecf54ca2f",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 1模式\n",
    "with open('./a.txt', mode='rb') as f:\n",
    "    f.seek(3,1)  \n",
    "    print(f.tell())\n",
    "    f.seek(4,1)    #从当前位置往后移动4字节\n",
    "    print(f.tell())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "id": "99abe9a7-3ec1-454f-adea-b8c3f7740d04",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 2模式\n",
    "with open('./a.txt', mode='r+t',encoding='utf-8') as f:\n",
    "    f.seek(9)  \n",
    "    f.write('<项目主任>')"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4f0a901b-bc25-4129-808a-e491dd74369d",
   "metadata": {},
   "source": [
    "注意：1.硬盘空间是无法修改的，硬盘中的数据更新都是用新内容覆盖旧内容\n",
    "2.内存中的数据是可以修改的\n",
    "### 文件修改方式一\n",
    "实现思路：将文件内容一次性全部读入"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "d6c52364-b7f7-4a6c-aa02-c04524dd1a96",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 文件修改方式\n",
    "\n",
    "with open('./db.txt', mode='rt', encoding='utf-8') as f:\n",
    "    data = f.read()\n",
    "    print(data)\n",
    "\n",
    "with open('./db.txt', mode='wt', encoding='utf-8') as f:\n",
    "    result = f.write(data.replace('kevin', '4747'))    # kevin必须存在才可以替换\n",
    "    print(result)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "1ae890b7-8d1f-412a-ba08-a53ab1310c26",
   "metadata": {},
   "source": [
    "### 文件修改方式二\n",
    "实现思路：以读的方式打开源文件，以写的方式打开另一个文件，一行行读取源文件内容，修改完成后写入临时文件，"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "id": "709906c1-f433-4eca-912c-d89218a99e49",
   "metadata": {},
   "outputs": [
    {
     "ename": "FileNotFoundError",
     "evalue": "[Errno 2] No such file or directory: './db.txt'",
     "output_type": "error",
     "traceback": [
      "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[1;31mFileNotFoundError\u001b[0m                         Traceback (most recent call last)",
      "Cell \u001b[1;32mIn[21], line 3\u001b[0m\n\u001b[0;32m      1\u001b[0m \u001b[38;5;28;01mimport\u001b[39;00m \u001b[38;5;21;01mos\u001b[39;00m\n\u001b[1;32m----> 3\u001b[0m \u001b[38;5;28;01mwith\u001b[39;00m \u001b[38;5;28mopen\u001b[39m(\u001b[38;5;124m'\u001b[39m\u001b[38;5;124m./db.txt\u001b[39m\u001b[38;5;124m'\u001b[39m, mode\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mrt\u001b[39m\u001b[38;5;124m'\u001b[39m, encoding\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mutf-8\u001b[39m\u001b[38;5;124m'\u001b[39m) \u001b[38;5;28;01mas\u001b[39;00m read_f,\u001b[38;5;28mopen\u001b[39m(\u001b[38;5;124m'\u001b[39m\u001b[38;5;124m./db.txt.swap\u001b[39m\u001b[38;5;124m'\u001b[39m,mode\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mwt\u001b[39m\u001b[38;5;124m'\u001b[39m,encoding\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mutf-8\u001b[39m\u001b[38;5;124m'\u001b[39m)  \u001b[38;5;28;01mas\u001b[39;00m write_f:\n\u001b[0;32m      4\u001b[0m     \u001b[38;5;28;01mfor\u001b[39;00m line \u001b[38;5;129;01min\u001b[39;00m read_f:\n\u001b[0;32m      5\u001b[0m         write_f\u001b[38;5;241m.\u001b[39mwrite(line\u001b[38;5;241m.\u001b[39mreplace(\u001b[38;5;124m'\u001b[39m\u001b[38;5;124m4747\u001b[39m\u001b[38;5;124m'\u001b[39m, \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mifconfig\u001b[39m\u001b[38;5;124m'\u001b[39m))\n",
      "File \u001b[1;32mD:\\anaconda3\\Lib\\site-packages\\IPython\\core\\interactiveshell.py:324\u001b[0m, in \u001b[0;36m_modified_open\u001b[1;34m(file, *args, **kwargs)\u001b[0m\n\u001b[0;32m    317\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m file \u001b[38;5;129;01min\u001b[39;00m {\u001b[38;5;241m0\u001b[39m, \u001b[38;5;241m1\u001b[39m, \u001b[38;5;241m2\u001b[39m}:\n\u001b[0;32m    318\u001b[0m     \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(\n\u001b[0;32m    319\u001b[0m         \u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mIPython won\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mt let you open fd=\u001b[39m\u001b[38;5;132;01m{\u001b[39;00mfile\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m by default \u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[0;32m    320\u001b[0m         \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mas it is likely to crash IPython. If you know what you are doing, \u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[0;32m    321\u001b[0m         \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124myou can use builtins\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124m open.\u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[0;32m    322\u001b[0m     )\n\u001b[1;32m--> 324\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m io_open(file, \u001b[38;5;241m*\u001b[39margs, \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mkwargs)\n",
      "\u001b[1;31mFileNotFoundError\u001b[0m: [Errno 2] No such file or directory: './db.txt'"
     ]
    }
   ],
   "source": [
    "import os\n",
    "\n",
    "with open('./db.txt', mode='rt', encoding='utf-8') as read_f,open('./db.txt.swap',mode='wt',encoding='utf-8')  as write_f:\n",
    "    for line in read_f:\n",
    "        write_f.write(line.replace('4747', 'ifconfig'))\n",
    "\n",
    "os.remove('db.txt')\n",
    "os.remove('db.txt.swap', 'db.txt')"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b618f73c-f3f6-409d-b7a7-0f7d1b42d4a0",
   "metadata": {},
   "source": [
    "## 使用读写模块，完成对学生管理系统的构建\n",
    "## 当用户输入信息的时候，就会保存在student_manage.txt文件中\n",
    "## 当用户修改学生信息时，对应的student_manage.txt文件信息也会更改\n",
    "## 当用户删除学生信息时，对应的student_manage.txt文件信息也会删除\n",
    "## 当用户查询学生信息时，对应的student_manage.txt文件信息就会被读取而显示在控制台上"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.12.4"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
